/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef __FRAMEWORK_CLASSES_CHECKEDITERATOR_HXX_
#define __FRAMEWORK_CLASSES_CHECKEDITERATOR_HXX_

//_________________________________________________________________________________________________________________
//	my own includes
//_________________________________________________________________________________________________________________

#include <macros/debug.hxx>

//_________________________________________________________________________________________________________________
//	interface includes
//_________________________________________________________________________________________________________________

//_________________________________________________________________________________________________________________
//	other includes
//_________________________________________________________________________________________________________________
#include <sal/types.h>

#ifndef __SGI_STL_ITERATOR
#include <iterator>
#endif

//_________________________________________________________________________________________________________________
//	namespace
//_________________________________________________________________________________________________________________

namespace framework{

//_________________________________________________________________________________________________________________
//	exported const
//_________________________________________________________________________________________________________________

//_________________________________________________________________________________________________________________
//	exported definitions
//_________________________________________________________________________________________________________________

/*-************************************************************************************************************//**
	@short          implement a iterator which support 2 end states!
	@descr			For our search methods we need a "walking" iterator object with special functionality!
					We must check for 3 different states of an iterator - normal position, exact end, after end.
					It's neccessary to detect if we have not found a entry and must return our default or
					default already returned and we must break loop!
					see using in class FilterCache too for further informations!

	@Attention		If your wish to debug this inline code ...
					under windows and msdev you can use "set ENVCFLAGS=/Ob0" to do that!

	@implements		-
	@base			-

	@devstatus		ready to use
	@threadsafe		no
*//*-*************************************************************************************************************/

template< class TContainer >
class CheckedIterator
{
	//-------------------------------------------------------------------------------------------------------------
	//	public methods
	//-------------------------------------------------------------------------------------------------------------

	public:

		//---------------------------------------------------------------------------------------------------------
		// constructor / destructor
		//---------------------------------------------------------------------------------------------------------

		/*-****************************************************************************************************//**
			@short		standard constructor
			@descr		Set default values on members.
						We set it internal to E_UNKNOWN to detect uninitialized instances of this class.
						If we found one - we know: "We must call initialize first!"

			@seealso	-

			@param		-
			@return		-

			@onerror	-
		*//*-*****************************************************************************************************/

		inline CheckedIterator()
                :   m_eEndState ( E_UNKNOWN )
                ,   m_pContainer( NULL      )
		{
		}

		//---------------------------------------------------------------------------------------------------------
		// interface methods
		//---------------------------------------------------------------------------------------------------------

		/*-****************************************************************************************************//**
			@short		initialize instance with valid container
			@descr		Set new container at an instance of this class. The other member will set automaticly!
						m_pPosition = first element in container
						m_eEndState = BEFOREEND

			@seealso	-

            @param      "rContainer", must be a valid reference to an existing container.
			@return		-

			@onerror	An assertion is thrown.
		*//*-*****************************************************************************************************/

        inline void initialize( const TContainer& rContainer )
		{
			// Check incoming parameter. We don't accept all!
            LOG_ASSERT2( &rContainer==NULL      , "CheckedIterator::initialize()", "Invalid parameter detected!"                        )
			LOG_ASSERT2( m_eEndState!=E_UNKNOWN	, "CheckedIterator::initialize()", "Instance already initialized! Don't do it again."	)

			if( m_eEndState == E_UNKNOWN )
			{
				// Set new container and actualize other member.
                m_pContainer = &rContainer          ;
                m_eEndState  = E_BEFOREEND          ;
                m_pPosition  = m_pContainer->begin();
			}
		}

		/*-****************************************************************************************************//**
			@short		set internal states to E_END
			@descr		Sometimes we need a "walking" check-iterator which is initialized with the END-state!
						We need it to return one default value if no other ones exist ...

			@seealso	using in class FilterCache!

			@param		-
			@return		-

			@onerror	-
		*//*-*****************************************************************************************************/

		inline void setEnd()
		{
            m_pContainer = NULL  ;
            m_eEndState  = E_END ;
		}

		/*-****************************************************************************************************//**
			@short		set internal states to E_AFTEREND
			@descr		Sometimes we need a "walking" check-iterator which is initialized with AFTEREND-state!
						We need it if we don't have a container but must prevent us against further searching!

			@seealso	using in class FilterCache!

			@param		-
			@return		-

			@onerror	-
		*//*-*****************************************************************************************************/

		inline void setAfterEnd()
		{
            m_pContainer = NULL       ;
            m_eEndState  = E_AFTEREND ;
		}

        /*-****************************************************************************************************//**
            @short      reset this iterator
            @descr      It must be called on an already initialized iterator.
                        Means the member m_pContainer must be valid. Otherwhise the reaction
                        isn't defined.

            @param      -
            @return     -

            @onerror    -
        *//*-*****************************************************************************************************/

        inline void reset()
        {
            m_eEndState  = E_UNKNOWN;
            m_pContainer = NULL;
        }

		/*-****************************************************************************************************//**
			@short		step to next element in container.
			@descr		If end of container is reached we change our internal "m_eEndState".
						If end reached for first time; we set it to E_END;
						If you step to next element again; we set it to E_AFTEREND.
						So you have a chance to differ between "exact end" and "after end"!

			@seealso	method isEnd()
			@seealso	method isAfterEnd()

			@param		-
			@return		A reference to our changed object himself.

			@onerror	-
		*//*-*****************************************************************************************************/

		inline CheckedIterator& operator++()
		{
			// Warn programmer if he forget to initailize object!
            LOG_ASSERT2( m_pContainer==NULL, "CheckedIterator::operator++()", "Object not initialized!" )
			// Step to next element if any exist or set our end states.
			switch( m_eEndState )
			{
				case E_BEFOREEND:	{
                                        ++m_pPosition;
                                        // If iterator reaching end ... set right state!
                                        if( m_pPosition == m_pContainer->end() )
										{
											m_eEndState = E_END;
										}
									}
									break;
				case E_END		:	{
                                        // Set state only ... iterator already points to end of container!
										m_eEndState = E_AFTEREND;
									}
									break;
			}
			return *this;
		}

		/*-****************************************************************************************************//**
			@short		return true if internal iterator was not initialized before
			@descr		These will be true, if use start a new search by using these iterator mechanism!

			@seealso	class FilterCache

			@param		-
			@return		True if internalk state E_UNKNOWN - false otherwise.

			@onerror	-
		*//*-*****************************************************************************************************/

		inline sal_Bool isUninitialized()
		{
			return( m_eEndState == E_UNKNOWN );
		}

		/*-****************************************************************************************************//**
			@short		return true if internal iterator reached end of container
			@descr		These will be true if you step to the end of internal container.

			@seealso	method isAfterEnd()

			@param		-
			@return		True if end reached; false otherwise.

			@onerror	-
		*//*-*****************************************************************************************************/

		inline sal_Bool isEnd()
		{
			// Is true if one end state is set!
			return	(
						( m_eEndState == E_END		)	||
						( m_eEndState == E_AFTEREND	)
					);
		}

		/*-****************************************************************************************************//**
			@short		return true if you call operator++ again and end already reached
			@descr		These indicate, that end already reached but you call operator++ again and again!

			@seealso	method isEnd()

			@param		-
			@return		True if end multiple reached; false otherwise.

			@onerror	-
		*//*-*****************************************************************************************************/

		inline sal_Bool isAfterEnd()
		{
			// Is true only, if special end state is set!
			return( m_eEndState == E_AFTEREND );
		}

		/*-****************************************************************************************************//**
			@short		support readonly access to container entry
			@descr		Use it to get the value of current container item.

			@seealso	-

			@param		-
			@return		A reference to value of container entry.

			@onerror	-
		*//*-*****************************************************************************************************/

		inline typename TContainer::const_iterator getEntry()
		{
			// Warn programmer if he forget to initialize these object ...
            LOG_ASSERT2( m_pContainer==NULL, "CheckedIterator::getEntry()", "Object not initialized!" )
			// or try to read a non existing element!
            LOG_ASSERT2( m_eEndState!=E_BEFOREEND, "CheckedIterator::getEntry()", "Wrong using of class detected!" )

            return m_pPosition;
		}

	//-------------------------------------------------------------------------------------------------------------
	//	private member
	//-------------------------------------------------------------------------------------------------------------

	private:

		// These enum defines our four states for an iterator position in curent container.
		enum EEndState
		{
			E_UNKNOWN	,
			E_BEFOREEND	,
			E_END		,
			E_AFTEREND
		};

        const TContainer*           m_pContainer    ;   // pointer to current container
        EEndState                   m_eEndState     ;   // "position state" of iterator!
        typename TContainer::const_iterator  m_pPosition     ;   // point to actual element in container
};

}		//	namespace framework

#endif	//	#ifndef __FRAMEWORK_CLASSES_CHECKEDITERATOR_HXX_
